#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "mcl/str.h"

#define TEST_STRING(X, Y) {if(strcmp(((X?X:"(NULL)")), ((Y?Y:"(NULL)")))) \
                           {fprintf(stderr, "%s:%d (loop #%d): %s!=%s ... Error: %d\n", __FILE__, __LINE__, i, (X), (Y), mcl_str_status(X)); exit(1);}}
#define TEST_LOGIC(X) {if(!(X)) {fprintf(stderr, "%s:%d: LOGIC TEST RETURNED FALSE\n", __FILE__, __LINE__); exit(1);}}
/*
*/

int main(){
   mcl_str_match_t* loc;
   mcl_str_t *s, *p;
   char *r;
   int i, j;
   
   for (i=0;i<12;++i){      
      /* Testing mcl_str family */
      s=mcl_str("This is a mcl string,");                                      TEST_STRING(s, "This is a mcl string,");
      p=mcl_str_cz(s);                                                          TEST_STRING(s, p);

      /* Testing mcl_str_cat family FIXME*/
      s=mcl_str_cat(s, 
      " which is fully compatible with normal char * strings btw.");            TEST_STRING(s, 
                                                                                "This is a mcl string, which is fully compatible with normal char * strings btw.");
      
      /* Testing mcl_str_insert FIXME TODO: Regex?*/
      /*p=mcl_str_insert(s, '*', "* strings, which make them awesome");         TEST_STRING(p, "This is a mcl string, which is fully compatible with normal char "
                                                                                               "* strings, which make them awesome strings btw.");
                                                                                                  
      /* Testing the str_free function */
      s=mcl_str_free(s);
      p=mcl_str_free(p);
      
      
      
      /* Testing mcl_str_sub :DONE:*/
      /*(NULL) should never occur, but that was the only way to stop the warnings without ridiculus gcc options */
      #define sub_cz_test(START, LENGTH, EXPECTED) {\
         s=mcl_str_sub_cz(p, START, LENGTH);\
         if (EXPECTED && !s) {fprintf(stderr, "%s:%d (loop #%d): Expected a string but null was returned\n", __FILE__, __LINE__, i); exit(1);}\
         if (!EXPECTED){\
            TEST_LOGIC(mcl_str_status(s)==MCL_STR_EINDEX);\
         }\
         else{\
            TEST_STRING(s, (EXPECTED?EXPECTED:"(NULL)"));\
         }\
         s=mcl_str_free(s);\
      }
      /*posibilities
         length:
            1. negative: 
               13. other than -1: invalid 
               14. -1: valid
            2. positive: depends
               3. longer then string length+ start point: invalid
               4. shorter or equel: valid
            5. zero: valid
         start:
            6. negative: 
               9.  valid only when absolute value is less then or equel to str length
               10. other: invalid 
            7. positive: 
               11. valid only when value is less then length
               12. other: invalid
            8. zero: valid
      */
      p=mcl_str("abcd");
      sub_cz_test(0, -4, NULL);     // #13
      sub_cz_test(0, 5, NULL);      // #3
      sub_cz_test(0, -1, "abcd");   // #14
      sub_cz_test(0, 0, "");        // #5 
      sub_cz_test(0, 3, "abc");     // #4
      sub_cz_test(1, 3, "bcd");     // #4
      sub_cz_test(0, 0, "");        // #5
      
      sub_cz_test(-3, 2, "bc");     // #9
      sub_cz_test(-4, 4, "abcd");   // #9
      sub_cz_test(-4, -1, "abcd");  // #9
      sub_cz_test(-1, 1, "d");      // #9
      sub_cz_test(-5, 0, NULL);     // #10
      sub_cz_test(0, -1, "abcd");   // #8
      sub_cz_test(4, 0, NULL);      // #12
      sub_cz_test(5, 0, NULL);      // #12
      sub_cz_test(3, 0, "");        // #11
      
      // misc mixen
      sub_cz_test(-3, 3, "bcd");
      sub_cz_test(1, 4, NULL);
      sub_cz_test(0, 4, "abcd");
      sub_cz_test(2, -1, "cd");
      sub_cz_test(4, -4, NULL);
      
      p=mcl_str_free(p);
      
      /* Testing mcl_str_match family (TODO regex)*/
      char *m1 = "potato tomato tomato potato", *m2 = "ato";
      loc=mcl_str_match_c(m1, m2);
      TEST_LOGIC(loc->count==4);
      for (j=0;j<loc->count; ++j) 
         TEST_LOGIC(!(strncmp(m1+(loc->selections[j]).start, m2, (loc->selections[j]).length)));
      mcl_str_match_free(loc);
      //mcl_str_mprobe
      
      /* mcl_str_insert_z */
      mcl_str_t *lebinz=mcl_str("FUN FACT: lebinz invented calculus!");
      mcl_str_t *otherguy=mcl_str("newton");
      lebinz=mcl_str_insert_z(lebinz, otherguy, strlen("FUN FACT: "), strlen("lebinz"));  TEST_STRING(lebinz, "FUN FACT: newton invented calculus!");
      
      mcl_str_free(otherguy);otherguy=mcl_str("NY LITTLE POKEMON DOT COM");
      lebinz=mcl_str_insert_z(lebinz, otherguy, 3, 5);                          TEST_STRING(lebinz, "FUNNY LITTLE POKEMON DOT COM: newton invented calculus!");
      
      mcl_str_free(lebinz);
      lebinz=mcl_str("12345");
      lebinz=mcl_str_insert(lebinz, "-----", 2, 0);                             TEST_STRING(lebinz, "12-----345");
      
      mcl_str_free(lebinz);
      lebinz=mcl_str("12345");
      lebinz=mcl_str_insert(lebinz, "", 2, 2);                                  TEST_STRING(lebinz, "125");
      
      TEST_LOGIC(mcl_str_len(lebinz)==3);                                        
      
      mcl_str_free(otherguy);
      otherguy=mcl_str("monster pokets");
      lebinz=mcl_str_replace_z(lebinz, "2", otherguy);                    TEST_STRING(lebinz, "1monster pokets5");
      lebinz=mcl_str_match_delete(lebinz, "monster");                           TEST_STRING(lebinz, "1 pokets5");
      lebinz=mcl_str_replace_z(lebinz, "ets5", otherguy);                 TEST_STRING(lebinz, "1monster pok");
      puts(lebinz);
      
      mcl_str_free(lebinz);
      mcl_str_free(otherguy);
   }
   return 0;
}
